import fs from 'fs';
import path from 'path';
import {getArgType} from '../modules';
let {
	dir,
	root,
	extension
} = require('./conf');

export class Collection {
	constructor(name){
		this.name = name;
		this.filepath = path.join(root,this.name+extension);
	}
	async readCollection(save){
		let data = await fsReadFile(this.filepath);
		try{
			data = JSON.parse(data);
		}catch(e){
			data = [];
		}
		if(save) this.cacheData = data;
		return data;
	}
	async writeCollection(datas){
		await fsWriteFile(this.filepath,JSON.stringify(datas));
		let d = await this.readCollection(true);
		return d;
	}
	async getCache(){
		let cache = this.cacheData || await this.readCollection(true);
		return cache;
	}
	async insert(item){
		// col.insert({a:1})
		// col.insert([{a:1},{b:2}])
		let data = await this.getCache();
		if (item.length>1) {
			data = data.concat(item);
		}else{
			data.push(item);
		}
		await this.writeCollection(data);
		return data;
	}
	async remove(condition){
		// col.remove({a:1,b:2})
		let data = await this.getCache();
		if (data.length) {
			data = data.filter(d=>!this.filterOnce(d,condition));
		}
		await this.writeCollection(data);
	}
	async update(condition,_item){
		// col.update({a:3},{b:90});
		let data = await this.getCache();
		data.forEach((d,i)=>{
			if (this.filterOnce(d,condition)) {
				data[i] = extend(d,_item);
			}
		});
		await this.writeCollection(data);
		return data;
	}
	filterOnce(item,condition){
		let ckeys = Object.keys(condition);
		return ckeys.map(key=>item[key]===condition[key]||(getArgType(condition[key])==='regexp'&&condition[key].test(item[key]))).every(b=>b);
	}	
	async find(condition,filter){
		// col.find({a:1,b:2},{pswd:0})
		let hasFilter = filter&&getArgType(filter)==='object';
		let data = JSON.parse(JSON.stringify(await this.getCache()));

		if ((condition===undefined||!Object.keys(condition).length)&&!hasFilter) return data;
		if (data.length) {
			let _data = data.filter(d=>this.filterOnce(d,condition));
			if (hasFilter) {
				_data = _data.map(d=>{
					for(let k in d){
						if (filter[k]!==undefined&&!filter[k]) delete d[k];
					}
					return d;
				});
			}
			return _data;
		}
		return [];
	}

}

function fsReadFile(fpath){
	return new Promise((resolve,reject)=>{
		fs.readFile(fpath,'utf8',(err,data)=>{
			if (err) {
				reject(err);
			}else{
				resolve(data);
			}
		});
	});
}
function fsWriteFile(fpath,datas){
	return new Promise((resolve,reject)=>{
		fs.writeFile(fpath,datas,err=>{
			if (err) {
				reject(err);
			}else{
				resolve('w');
			}
		});
	});
}

function extend(){
	// extend(target,{},{},...)
	let objs=arguments;
	if (objs.length<=1) return objs[0];
	
	let _extend = (a,b)=>{
		if (getArgType(b)=='object') {
			for(let j in b){
				if(getArgType(b[j])=='object'){
					a[j]=_extend(a[j]||{},b[j]);
				}else{
					a[j]=b[j];
				}
			}
		};
		return a;
	}
	let res=_extend({},objs[0]);
	for(let i=1;i<objs.length;i++) _extend(res,objs[i]);
	return res;
};


